<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D Bouncing Balls Network</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
    <style>
        body {
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: #000;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <script>
        let balls = [];
        const numBalls = 100;
        const containerRadius = 200;
        let containerRotation = 0;
        let rotX = 0;
        let rotY = 0;
        
        class Ball {
            constructor() {
                this.radius = random(3, 6);
                this.color = color(random(100, 255), random(100, 255), random(100, 255), 220);
                this.reset();
            }

            reset() {
                // 在3D球体内部随机分布
                let r = random(0, containerRadius * 0.9);
                let theta = random(0, PI * 2);
                let phi = random(0, PI);
                
                this.x = r * sin(phi) * cos(theta);
                this.y = r * sin(phi) * sin(theta);
                this.z = r * cos(phi);
                
                this.speedX = random(-1, 1);
                this.speedY = random(-1, 1);
                this.speedZ = random(-1, 1);
                this.connections = [];
            }

            update() {
                this.x += this.speedX;
                this.y += this.speedY;
                this.z += this.speedZ;

                // 计算到中心的距离
                let distance = sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
                
                // 如果碰到容器边界，反弹
                if (distance + this.radius > containerRadius) {
                    // 计算反弹方向
                    let nx = this.x / distance;
                    let ny = this.y / distance;
                    let nz = this.z / distance;
                    
                    // 计算反弹速度
                    let dotProduct = this.speedX * nx + this.speedY * ny + this.speedZ * nz;
                    this.speedX = this.speedX - 2 * dotProduct * nx;
                    this.speedY = this.speedY - 2 * dotProduct * ny;
                    this.speedZ = this.speedZ - 2 * dotProduct * nz;
                    
                    // 确保小球不会卡在边界
                    let adjustedRadius = containerRadius - this.radius - 1;
                    this.x = nx * adjustedRadius;
                    this.y = ny * adjustedRadius;
                    this.z = nz * adjustedRadius;
                }
            }

            display() {
                push();
                translate(this.x, this.y, this.z);
                noStroke();
                fill(this.color);
                sphere(this.radius);
                pop();
            }

            findConnections(allBalls) {
                this.connections = [];
                for (let i = 0; i < allBalls.length; i++) {
                    if (allBalls[i] !== this) {
                        let dist = calculateDistance3D(
                            this.x, this.y, this.z, 
                            allBalls[i].x, allBalls[i].y, allBalls[i].z
                        );
                        if (dist < 40) {
                            this.connections.push(i);
                        }
                    }
                }
            }

            drawConnections(allBalls) {
                for (let i of this.connections) {
                    let ball = allBalls[i];
                    // 计算线的颜色为两个球的混合
                    let lineColor = lerpColor(this.color, ball.color, 0.5);
                    stroke(lineColor);
                    strokeWeight(0.5);
                    line(this.x, this.y, this.z, ball.x, ball.y, ball.z);
                }
            }
        }

        function calculateDistance3D(x1, y1, z1, x2, y2, z2) {
            return sqrt(
                (x2 - x1) * (x2 - x1) + 
                (y2 - y1) * (y2 - y1) + 
                (z2 - z1) * (z2 - z1)
            );
        }

        function setup() {
            createCanvas(windowWidth, windowHeight, WEBGL);
            
            for (let i = 0; i < numBalls; i++) {
                balls.push(new Ball());
            }
            
            // 初始化连接
            updateConnections();
            
            // 设置文字
            textSize(36);
            textAlign(CENTER, CENTER);
            textStyle(BOLD);
        }

        function updateConnections() {
            for (let ball of balls) {
                ball.findConnections(balls);
            }
        }

        function mouseDragged() {
            rotY += (mouseX - pmouseX) * 0.01;
            rotX += (mouseY - pmouseY) * 0.01;
        }

        function draw() {
            background(0);
            
            // 添加光源
            ambientLight(50);
            pointLight(255, 255, 255, 0, 0, 300);
            
            // 自动旋转 + 鼠标控制
            if (!mouseIsPressed) {
                rotY += 0.005;
                rotX = sin(frameCount * 0.01) * 0.3;
            }
            
            // 应用旋转
            rotateY(rotY);
            rotateX(rotX);
            
            // 绘制连接线
            for (let ball of balls) {
                ball.drawConnections(balls);
            }
            
            // 更新和显示所有小球
            for (let ball of balls) {
                ball.update();
                ball.display();
            }
            
            // 每隔一段时间更新连接
            if (frameCount % 30 === 0) {
                updateConnections();
            }
            
            // 绘制透明球体容器
            noFill();
            stroke(100);
            strokeWeight(1);
            sphere(containerRadius);
            
            // 在底部显示文字
            push();
            rotateY(-rotY);
            rotateX(-rotX);
            translate(0, height/3, 0);
            fill(255);
            noStroke();
            text("小球在大球里", 0, 0);
            pop();
        }

        function windowResized() {
            resizeCanvas(windowWidth, windowHeight);
        }
    </script>
</body>
</html> 